EuroSys'16 Best Paper
This paper supports the author's following work, graphene(-SGX).
This paper analyzes the vulnerability space arising in Trusted Execution Environments (TEEs) when interfacing a trusted enclave application with untrusted, potentially malicious code. Considerable research and industry effort has gone into developing TEE runtime libraries with the purpose of transparently shielding enclave application code from an adversarial environment. However, our analysis reveals that shielding requirements are generally not well-understood in real-world TEE runtime implementations. We expose several sanitization vulnerabilities at the level of the Application Binary Interface (ABI) and the Application Programming Interface (API) that can lead to exploitable memory safety and side-channel vulnerabilities in the compiled enclave. Mitigation of these vulnerabilities is not as simple as ensuring that pointers are outside enclave memory. In fact, we demonstrate that state-of-the-art mitigation techniques such as Intel's edger8r, Microsoft's "deep copy marshalling", or even memory-safe languages like Rust fail to fully eliminate this attack surface. Our analysis reveals 35 enclave interface sanitization vulnerabilities in 8 major open-source shielding frameworks for Intel SGX, RISC-V, and Sancus TEEs. We practically exploit these vulnerabilities in several attack scenarios to leak secret keys from the enclave or enable remote code reuse. We have responsibly disclosed our findings, leading to 5 designated CVE records and numerous security patches in the vulnerable open-source projects, including the Intel SGX-SDK, Microsoft Open Enclave, Google Asylo, and the Rust compiler.
Entry status flags sanitization
Entry stack pointer restore
Exit register leakage
Missing pointer range check
Null-terminated string handling
Integer overflow in range check
Incorrect pointer range check
Double fetch untrusted pointer
Ocall return value not checked
Uninitialized padding leakage
SGX-SDK
OpenEnclave
Graphene
SGX-LKL
Rust-EDP
Asylo
Keystone
Sancus
that legacy applications may also make implicit assumptions on the validity of argv and envp pointers, which are not the result of system calls.
WebAssembly in SGX
Remote computation has numerous use cases such as cloud computing, client-side web applications or volunteer computing. Typically, these computations are executed inside a sandboxed environment for two reasons: first, to isolate the execution in order to protect the host environment from unauthorised access, and second to control and restrict resource usage. Often, there is mutual distrust between entities providing the code and the ones executing it, owing to concerns over three potential problems: (i) loss of control over code and data by the providing entity, (ii) uncertainty of the integrity of the execution environment for customers, and (iii) a missing mutually trusted accounting of resource usage.
In this paper we present AccTEE, a two-way sandbox that offers remote computation with resource accounting trusted by consumers and providers. AccTEE leverages two recent technologies: hardware-protected trusted execution environments, and Web-Assembly, a novel platform independent byte-code format. We show how AccTEE uses automated code instrumentation for fine-grained resource accounting while maintaining confidentiality and integrity of code and data. Our evaluation of AccTEE in three scenarios – volunteer computing, serverless computing, and pay-by-computation for the web – shows a maximum accounting overhead of 10%.
USENIX'20
Kernel-mode drivers are challenging to analyze for vulnerabilities, yet play a critical role in maintaining the security of OS kernels. Their wide attack surface, exposed via both the system call interface and the peripheral interface, is often found to be the most direct attack vector to compromise an OS kernel. Researchers therefore have proposed many fuzzing techniques to find vulnerabilities in kernel drivers. However, the performance of kernel fuzzers is still lacking, for reasons such as prolonged execution of kernel code, interference between test inputs, and kernel crashes.
This paper proposes lightweight virtual machine checkpointing as a new primitive that enables high-throughput kernel driver fuzzing. Our key insight is that kernel driver fuzzers frequently execute similar test cases in a row, and that their performance can be improved by dynamically creating multiple checkpoints while executing test cases and skipping parts of test cases using the created checkpoints. We built a system, dubbed Agamotto, around the virtual machine checkpointing primitive and evaluated it by fuzzing the peripheral attack surface of USB and PCI drivers in Linux. The results are convincing. Agamotto improved the performance of the state-of-the-art kernel fuzzer, Syzkaller, by 66.6% on average in fuzzing 8 USB drivers, and an AFL-based PCI fuzzer by 21.6% in fuzzing 4 PCI drivers, without modifying their underlying input generation algorithm.
Filesystem + Formal Method + SGX
New trusted computing primitives such as Intel SGX have shown the feasibility of running user-level applications in enclaves on a commodity trusted processor without trusting a large OS. However, the OS can still compromise the integrity of an enclave by tampering with the system call return values. In fact, it has been shown that a subclass of these attacks, called Iago attacks, enables arbitrary logic execution in enclave programs. Existing enclave systems have very large TCB and they implement ad-hoc checks at the system call interface which are hard to verify for completeness. To this end, we present BesFS—the first filesystem interface which provably protects the enclave integrity against a completely malicious OS. We prove 167 lemmas and 2 key theorems in 4625 lines of Coq proof scripts, which directly proves the safety properties of the BesFS specification. BesFS comprises of 15 APIs with compositional safety and is expressive enough to support 31 real applications we test. BesFS integrates into existing SGX-enabled applications with minimal impact to TCB. BesFS can serve as a reference implementation for hand-coded API checks.
SGX to protect GPU then prevent cheating
Online gaming, with a reported 152 billion US dollar market, is immensely popular today. One of the critical issues in multiplayer online games is cheating, in which a player uses an illegal methodology to create an advantage beyond honest game play. For example, wallhacks, the main focus of this work, animate enemy objects on a cheating player's screen, despite being actually hidden behind walls (or other occluding objects). Since such cheats discourage honest players and cause game companies to lose revenue, gaming companies deploy mitigation solutions alongside game applications on the player's machine. However, their solutions are fundamentally flawed since they are deployed on a machine where the attacker has absolute control.
ASPLOS 2020
Intel SGX is a hardware-based trusted execution environment (TEE), which enables an application to compute on confidential data in a secure enclave. SGX assumes a powerful threat model, in which only the CPU itself is trusted; anything else is untrusted, including the memory, firmware, system software, etc. An enclave interacts with its host application through an exposed, enclave-specific, (usually) bi-directional interface. This interface is the main attack surface of the enclave. The attacker can invoke the interface in any order and inputs. It is thus imperative to secure it through careful design and defensive programming.
In this work, we systematically analyze the attack models against the enclave untrusted interfaces and summarized them into the COIN attacks -- Concurrent, Order, Inputs, and Nested. Together, these four models allow the attacker to invoke the enclave interface in any order with arbitrary inputs, including from multiple threads. We then build an extensible framework to test an enclave in the presence of COIN attacks with instruction emulation and concolic execution. We evaluated ten popular open-source SGX projects using eight vulnerability detection policies that cover information leaks, control-flow hijackings, and memory vulnerabilities. We found 52 vulnerabilities. In one case, we discovered an information leak that could reliably dump the entire enclave memory by manipulating the inputs. Our evaluation highlights the necessity of extensively testing an enclave before its deployment.
To find vulnerabilities of SGX applications in four models:
Concurrent calls: multithread, race condition, improper lock…
Order: assumes the calling sequence
Input manipulation: bad OCALL return val & ECALL arguments
Nested calls: calling OCALL that invokes ECALL, not implemented
The design of COIN:


Emulation: QEMU
Symbolic execution: Triton (backed by z3)
Policy-based vulnerability discovery
COIN uses 8 policies to find the potential vulnerabilities:
Heap info leak
Stack info leak
Ineffectual condition
Use after free
Double free
Stack overflow
Heap overflow
Null pointer dereference
Symbolic execution + emulation
Policies can be configurable
Real world problems
nested call left unimplemented
May not be powerful enough to deal with complicate situations
Policies are mainly at relatively low-level
The presence of large numbers of security vulnerabilities in popular feature-rich commodity operating systems has inspired a long line of work on excluding these operating systems from the trusted computing base of applications, while retaining many of their benefits. Legacy applications continue to run on the untrusted operating system, while a small hyper visor or trusted hardware prevents the operating system from accessing the applications' memory. In this paper, we introduce controlled-channel attacks, a new type of side-channel attack that allows an untrusted operating system to extract large amounts of sensitive information from protected applications on systems like Overshadow, Ink Tag or Haven. We implement the attacks on Haven and Ink Tag and demonstrate their power by extracting complete text documents and outlines of JPEG images from widely deployed application libraries. Given these attacks, it is unclear if Over shadow's vision of protecting unmodified legacy applications from legacy operating systems running on off-the-shelf hardware is still tenable.
The key intuition is to exploit the fact that a regular applicationusually shows different patterns in control transfers or data accesses when the sensitive data it is processing are different.
Source: Wikipedia
![]()
| 编号 | 名称 | 性质 | 连脑部位 | 进出颅腔部位 | 核团 | 功能 |
|---|---|---|---|---|---|---|
| 0 | 终末神经 | ? | 終板 | 篩板 | 中隔內核(Septal nuclei) | 和費洛蒙的感測有關 |
| I | 嗅神经 | 感觉性 | 端脑 | 篩板 | 嗅前核(Anterior olfactory nucleus) | 传递嗅觉信息 |
| II | 視神經 | 感觉性 | 间脑 | 視神經管(Optic canal) | 视网膜神经节细胞[5] | 向大脑传递视觉信息 |
| III | 动眼神经 | 运动性 | 中脑前部 | 眶上裂(Superior orbital fissure) | 动眼神经核(Oculomotor nucleus) | 支配上瞼舉肌(英语:Levator palpebrae superioris),上直肌、内直肌、下直肌和下斜肌,来协同完成眼球的运动;支配瞳孔括约肌和睫状体的收缩。 |
| IV | 滑车神经 | 运动性 | 中脑后部 | 眶上裂 | 滑车神经核(Trochlear nucleus) | 支配上斜肌(Superior oblique muscle),来控制眼球的水平或者汇聚运动 |
| V | 三叉神经 | 混合性 | 橋腦 | 眶上裂(眼神经),圆孔(上颌神经),卵圆孔(下颌神经) | 三叉神经核感觉主核,三叉神经脊束核,中脑三叉神经核,三叉神经运动核 | 接受面部的感觉输入;支配咀嚼肌的收缩 |
| VI | 外旋神經 | 运动性 | 橋腦前缘 | 眶上裂 | 外展神经核 | 支配外直肌 |
| VII | 顏面神經 | 混合性 | 橋腦(橄榄核之上桥小脑角部位) | 内耳道、莖乳突孔(Stylomastoid foramen) | 面神经核、孤束核、上涎神经核 | 接收舌肌前三分之二部位的感觉输入;支配面部表情肌、二腹肌、镫骨肌;支配唾液腺和泪腺的分泌。 |
| VIII | 前庭耳蝸神經 | 感觉性 | 橋腦 | 内耳道 | 前庭神经核、耳蜗核 | 接受声音、旋转、重力(对保持平衡和运动非常重要)的感觉输入。前庭分支和耳蜗分支主要传递听觉。 |
| IX | 舌咽神经 | 混合性 | 延腦 | 頸靜脈孔(Jugular foramen) | 疑核、下涎核、孤束核 | 接受舌部后三分之一的感觉输入;部分感觉经腭扁桃体传递到脑;支配腮腺的分泌;支配茎突的运动。 |
| X | 迷走神经 | 混合性 | 延腦 | 頸靜脈孔 | 疑核、背运动迷走神经核、孤束核 | 接受来自会咽的特殊味觉输入;支配喉部肌肉和咽肌(有舌咽神经支配的茎突除外);提供了几乎所有的胸、腹部和内臟的副交感神经纤维。主要功能:控制发声肌肉、软腭和共振。损害症状:吞咽困难與腭咽闭合不全。 |
| XI | 副神经 | 运动性 | 延腦 | 頸靜脈孔 | 孤束核、脊髓副神经核 | 支配胸锁乳突肌与斜方肌,与迷走神经(CN X)功能有部分重叠。损害症状:不能耸肩,头部运动变弱。 |
| XII | 舌下神经 | 混合性 | 延腦 | 舌下神经管(Hypoglossal foramen) | 舌下神经核 | 支配舌部肌肉的运动(由迷走神经支配的舌腭肌除外);对吞咽和语音清晰度非常重要。舌部的肌肉的感覺。 |

As control-flow hijacking defenses gain adoption, it is important to understand the remaining capabilities of adversaries via memory exploits. Non-control data exploits are used to mount information leakage attacks or privilege escalation attacks program memory. Compared to control-flow hijacking attacks, such non-control data exploits have limited expressiveness, however, the question is: what is the real expressive power of non-control data attacks? In this paper we show that such attacks are Turing-complete. We present a systematic technique called data-oriented programming (DOP) to construct expressive non-control data exploits for arbitrary x86 programs. In the experimental evaluation using 9 programs, we identified 7518 data-oriented x86 gadgets and 5052 gadget dispatchers, which are the building blocks for DOP. 8 out of 9 real-world programs have gadgets to simulate arbitrary computations and 2 of them are confirmed to be able to build Turing-complete attacks. We build 3 end-to-end attacks to bypass randomization defenses without leaking addresses, to run a network bot which takes commands from the attacker, and to alter the memory permissions. All the attacks work in the presence of ASLR and DEP, demonstrating how the expressiveness offered by DOP significantly empowers the attacker.
There are no function call gadgets in data-oriented programming, as it does not change the control data.
We introduce a new concept called brokered delegation. Brokered delegation allows users to flexibly delegate credentials and rights for a range of service providers to other users and third parties. We explore how brokered delegation can be implemented using novel trusted execution environments (TEEs). We introduce a system called DelegaTEE that enables users (Delegatees) to log into different online services using the credentials of other users (Owners). Credentials in DelegaTEE are never revealed to Delegatees and Owners can restrict access to their accounts using a range of rich, contextually dependent delegation policies.
DelegaTEE fundamentally shifts existing access control models for centralized online services. It does so by using TEEs to permit access delegation at the user's discretion. DelegaTEE thus effectively reduces mandatory access control (MAC) in this context to discretionary access control (DAC). The system demonstrates the significant potential for TEEs to create new forms of resource sharing around online services without the direct support from those services.
We present a full implementation of DelegaTEE using Intel SGX and demonstrate its use in four real-world applications: email access (SMTP/IMAP), restricted website access using a HTTPS proxy, e-banking/credit card, and a third-party payment system (PayPal).
ICSE'19
Side-channel attacks allow an adversary to uncover secret program data by observing the behavior of a program with respect to a resource, such as execution time, consumed memory or response size. Side-channel vulnerabilities are difficult to reason about as they involve analyzing the correlations between resource usage over multiple program paths. We present DifFuzz, a fuzzing-based approach for detecting side-channel vulnerabilities related to time and space. DifFuzz automatically detects these vulnerabilities by analyzing two versions of the program and using resource-guided heuristics to find inputs that maximize the difference in resource consumption between secret-dependent paths. The methodology of DifFuzz is general and can be applied to programs written in any language. For this paper, we present an implementation that targets analysis of Java programs, and uses and extends the Kelinci and AFL fuzzers. We evaluate DifFuzz on a large number of Java programs and demonstrate that it can reveal unknown side-channel vulnerabilities in popular applications. We also show that DifFuzz compares favorably against Blazer and Themis, two state-of-the-art analysis tools for finding side-channels in Java programs.
Old version: Binary Compatibility For SGX Enclaves
Yet another middleware to support unmodified binary to run in SGX enclave. This is done through dynamically rewrite binary inside the encalve.
Enclaves, such as those enabled by Intel SGX, offer a hardware primitive for shielding user-level applications from the OS. While enclaves are a useful starting point, code running in the enclave requires additional checks whenever control or data is transferred to/from the untrusted OS. The enclave-OS interface on SGX, however, can be extremely large if we wish to run existing unmodified binaries inside enclaves. This paper presents Ratel, a dynamic binary translation engine running inside SGX enclaves on Linux. Ratel offers complete interposition, the ability to interpose on all executed instructions in the enclave and monitor all interactions with the OS. Instruction-level interposition offers a general foundation for implementing a large variety of inline security monitors in the future.
We take a principled approach in explaining why complete interposition on SGX is challenging. We draw attention to 5 design decisions in SGX that create fundamental trade-offs between performance and ensuring complete interposition, and we explain how to resolve them in the favor of complete interposition. To illustrate the utility of the Ratel framework, we present the first attempt to offer binary compatibility with existing software on SGX. We report that Ratel offers binary compatibility with over 200 programs we tested, including micro-benchmarks and real applications such as Linux shell utilities. Runtimes for two programming languages, namely Python and R, tested with standard benchmarks work out-of-the-box on Ratel without any specialized handling.
There has been interest in mechanisms that enable the secure use of legacy code to implement trusted code in a Trusted Execution Environment (TEE), such as Intel SGX. However, because legacy code generally assumes the presence of an operating system, this naturally raises the spectre of Iago attacks on the legacy code. We observe that not all legacy code is vulnerable to Iago attacks and that legacy code must use return values from system calls in an unsafe way to have Iago vulnerabilities.
Based on this observation, we develop Emilia, which automatically detects Iago vulnerabilities in legacy applications by fuzzing applications using system call return values. We use Emilia to discover 51 Iago vulnerabilities in 17 applications, and find that Iago vulnerabilities are widespread and common. We conduct an in-depth analysis of the vulnerabilities we found and conclude that while common, the majority (82.4%) can be mitigated with simple, stateless checks in the system call forwarding layer, while the rest are best fixed by finding and patching them in the legacy code. Finally, we study and evaluate different trade-offs in the design of Emilia.
strace (to intercept syscall return value)to be continued
Graphene-SGX: A Practical Library OS for Unmodified Applications on SGX
LibOS in enclave + unmodified binary
Intel SGX hardware enables applications to protect themselves from potentially-malicious OSes or hypervisors. In cloud computing and other systems, many users and applications could benefit from SGX. Unfortunately, current applications will not work out-of-the-box on SGX. Although previous work has shown that a library OS can execute unmodified applications on SGX, a belief has developed that a library OS will be ruinous for performance and TCB size, making application code modification an implicit prerequisite to adopting SGX.
This paper demonstrates that these concerns are exaggerated, and that a fully-featured library OS can rapidly deploy unmodified applications on SGX with overheads comparable to applications modified to use “shim” layers. We present a port of Graphene to SGX, as well as a number of improvements to make the security benefits of SGX more usable, such as integrity support for dynamically-loaded libraries, and secure multi-process support. Graphene-SGX supports a wide range of unmodified applications, including Apache, GCC, and the R interpreter. The performance overheads of Graphene- SGX range from matching a Linux process to less than 2× in most single-process cases; these overheads are largely attributable to current SGX hardware or missed opportunities to optimize Graphene internals, and are not necessarily fundamental to leaving the application unmodified. Graphene-SGX is open-source and has been used concurrently by other groups for SGX research.
Intel has introduced a hardware-based trusted execution environment, Intel Software Guard Extensions (SGX), that provides a secure, isolated execution environment, or enclave, for a user program without trusting any underlying software (e.g., an operating system) or firmware. Researchers have demonstrated that SGX is vulnerable to a page-fault-based attack. However, the attack only reveals page-level memory accesses within an enclave.
In this paper, we explore a new, yet critical, sidechannel attack, branch shadowing, that reveals fine-grained control flows (branch granularity) in an enclave. The root cause of this attack is that SGX does not clear branch history when switching from enclave to non-enclave mode, leaving fine-grained traces for the outside world to observe, which gives rise to a branch-prediction side channel. However, exploiting this channel in practice is challenging because 1) measuring branch execution time is too noisy for distinguishing fine-grained control-flow changes and 2) pausing an enclave right after it has executed the code block we target requires sophisticated control. To overcome these challenges, we develop two novel exploitation techniques: 1) a last branch record (LBR)-based history-inferring technique and 2) an advanced programmable interrupt controller (APIC)-based technique to control the execution of an enclave in a fine-grained manner. An evaluation against RSA shows that our attack infers each private key bit with 99.8% accuracy. Finally, we thoroughly study the feasibility of hardware-based solutions (i.e., branch history flushing) and propose a software-based approach that mitigates the attack.
现在我采用的方案是 TiddlyWiki Server 的目录放在我的 Github Pages 主页中,然后每次commit之前重新生成一个 html 链接在主站上面。
我使用了一些插件来支持markdown, LaTeX 等常用组件。
List all under a tag:<<list-links "[tag[SGX]]">>
List tiddlers having two tags simultaneously: <<list-links "[tag[SGX]tag[Paper]]">>
USENIX Security 2020
Source code unavailable
Traditional TrustZone OSes and Applications is not easy to fuzz because they cannot be instrumented or modified easily in the original hardware environment. So to emulate them for fuzzing purpose.
Emulate TrustZone OSes(TZOS) and Trusted Applications (TAs)
Abstract and reimplement a subset of hardware/software interfaces
Fuzz these components
TZOSes: QSEE, Huawei, OPTEE, Kinibi, TEEGRIS(Samsung) & TAs

Re-host the TZOS frimware
Choose the components to reuse/emulate carefully
Bootloader
Secure Monitor
TEE driver and TEE userspace
MMIO registers (easy to emulate)
TriforceAFL + QEMU
Manually written Interfaces
Emulations works well. For upgraded TZOSes, only a few efforts are needed for compatibility.
Identifying the fuzzed target
Result stability (migrate to hardware, reproducibility)
Randomness
| Class | Vulnerability Types | Crashes |
|---|---|---|
| Availability | Null-pointer dereferences | 9 |
| Insufficient shared memory crashes | 10 | |
| Other | 8 | |
| Confidentiality | Read from attacker-controlled pointer to shared memory | 8 |
| Read from attacker-controlled | 0 | |
| OOB buffer length to shared memory | ||
| Integrity | Write to secure memory using attacker-controlled pointer | 11 |
| Write to secure memory using | 2 | |
| attacker-controlled OOB buffer length |
Just like the previous paper, the main causes of the crashes can be attributed to:
Assumptions of Normal-World Call Sequence
Unvalidated Pointers from Normal World
Unvalidated Types
Normal-World Checks
Assumptions of Normal-World Call Sequence
Solid work
Efforts taken to run TZOS and TA in emulation environment
Acceptable performance
Low coverage
Crashes -X-> vulnerabilities
https://github.com/intel/linux-sgx/blob/master/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp
protected_fs_file::protected_fs_file(const char* filename, const char* mode, const sgx_aes_gcm_128bit_key_t* import_key, const sgx_aes_gcm_128bit_key_t* kdk_key)
{
sgx_status_t status = SGX_SUCCESS;
uint8_t result = 0;
int32_t result32 = 0;
init_fields();
if (filename == NULL || mode == NULL ||
strnlen(filename, 1) == 0 || strnlen(mode, 1) == 0)
{
last_error = EINVAL;
return;
}
if (strnlen(filename, FULLNAME_MAX_LEN) >= FULLNAME_MAX_LEN - 1)
{
last_error = ENAMETOOLONG;
return;
}
if (import_key != NULL && kdk_key != NULL)
{// import key is used only with auto generated keys
last_error = EINVAL;
return;
}
status = sgx_create_report(NULL, NULL, &report);
if (status != SGX_SUCCESS)
{
last_error = status;
return;
}
result32 = sgx_thread_mutex_init(&mutex, NULL);
if (result32 != 0)
{
last_error = result32;
return;
}
if (init_session_master_key() == false)
// last_error already set
return;
if (kdk_key != NULL)
{
// for new file, this value will later be saved in the meta data plain part (init_new_file)
// for existing file, we will later compare this value with the value from the file (init_existing_file)
use_user_kdk_key = 1;
memcpy(user_kdk_key, kdk_key, sizeof(sgx_aes_gcm_128bit_key_t));
}
// get the clean file name (original name might be clean or with relative path or with absolute path...)
char clean_filename[FILENAME_MAX_LEN];
if (cleanup_filename(filename, clean_filename) == false)
// last_error already set
return;
if (import_key != NULL)
{// verify the key is not empty - note from SAFE review
sgx_aes_gcm_128bit_key_t empty_aes_key = {0};
if (consttime_memequal(import_key, &empty_aes_key, sizeof(sgx_aes_gcm_128bit_key_t)) == 1)
{
last_error = EINVAL;
return;
}
}
if (parse_mode(mode) == false)
{
last_error = EINVAL;
return;
}
status = u_sgxprotectedfs_check_if_file_exists(&result, filename); // if result == 1 --> file exists
if (status != SGX_SUCCESS)
{
last_error = status;
return;
}
if (open_mode.write == 1 && result == 1)
{// try to delete existing file
int32_t saved_errno = 0;
result32 = remove(filename);
if (result32 != 0)
{
// either can't delete or the file was already deleted by someone else
saved_errno = errno;
errno = 0;
}
// re-check
status = u_sgxprotectedfs_check_if_file_exists(&result, filename);
if (status != SGX_SUCCESS || result == 1)
{
last_error = (status != SGX_SUCCESS) ? status :
(saved_errno != 0) ? saved_errno : EACCES;
return;
}
}
if (open_mode.read == 1 && result == 0)
{// file must exists
last_error = ENOENT;
return;
}
if (import_key != NULL && result == 0)
{// file must exists - otherwise the user key is not used
last_error = ENOENT;
return;
}
// now open the file
read_only = (open_mode.read == 1 && open_mode.update == 0); // read only files can be opened simultaneously by many enclaves
do {
status = u_sgxprotectedfs_exclusive_file_open(&file, filename, read_only, &real_file_size, &result32);
if (status != SGX_SUCCESS || file == NULL)
{
last_error = (status != SGX_SUCCESS) ? status :
(result32 != 0) ? result32 : EACCES;
break;
}
if (real_file_size < 0)
{
last_error = EINVAL;
break;
}
if (real_file_size % NODE_SIZE != 0)
{
last_error = SGX_ERROR_FILE_NOT_SGX_FILE;
break;
}
strncpy(recovery_filename, filename, FULLNAME_MAX_LEN - 1); // copy full file name
recovery_filename[FULLNAME_MAX_LEN - 1] = '\0'; // just to be safe
size_t full_name_len = strnlen(recovery_filename, RECOVERY_FILE_MAX_LEN);
strncpy(&recovery_filename[full_name_len], "_recovery", 10);
if (real_file_size > 0)
{// existing file
if (open_mode.write == 1) // redundant check, just in case
{
last_error = EACCES;
break;
}
if (init_existing_file(filename, clean_filename, import_key) == false)
break;
if (open_mode.append == 1 && open_mode.update == 0)
offset = encrypted_part_plain.size;
}
else
{// new file
if (init_new_file(clean_filename) == false)
break;
}
file_status = SGX_FILE_STATUS_OK;
} while(0);
if (file_status != SGX_FILE_STATUS_OK)
{
if (file != NULL)
{
u_sgxprotectedfs_fclose(&result32, file); // we don't care about the result
file = NULL;
}
}
}
See also: C++ fwrite
size_t protected_fs_file::write(const void* ptr, size_t size, size_t count)
{
if (ptr == NULL || size == 0 || count == 0)
return 0;
int32_t result32 = sgx_thread_mutex_lock(&mutex);
if (result32 != 0)
{
last_error = result32;
file_status = SGX_FILE_STATUS_MEMORY_CORRUPTED;
return 0;
}
size_t data_left_to_write = size * count;
// prevent overlap...
#if defined(_WIN64) || defined(__x86_64__)
if (size > UINT32_MAX || count > UINT32_MAX)
{
last_error = EINVAL;
sgx_thread_mutex_unlock(&mutex);
return 0;
}
#else
if (((uint64_t)((uint64_t)size * (uint64_t)count)) != (uint64_t)data_left_to_write)
{
last_error = EINVAL;
sgx_thread_mutex_unlock(&mutex);
return 0;
}
#endif
if (sgx_is_outside_enclave(ptr, data_left_to_write))
{
last_error = SGX_ERROR_INVALID_PARAMETER;
sgx_thread_mutex_unlock(&mutex);
return 0;
}
if (file_status != SGX_FILE_STATUS_OK)
{
last_error = SGX_ERROR_FILE_BAD_STATUS;
sgx_thread_mutex_unlock(&mutex);
return 0;
}
if (open_mode.append == 0 && open_mode.update == 0 && open_mode.write == 0)
{
last_error = EACCES;
sgx_thread_mutex_unlock(&mutex);
return 0;
}
if (open_mode.append == 1)
offset = encrypted_part_plain.size; // add at the end of the file
const unsigned char* data_to_write = (const unsigned char*)ptr;
// the first block of user data is written in the meta-data encrypted part
if (offset < MD_USER_DATA_SIZE)
{
size_t empty_place_left_in_md = MD_USER_DATA_SIZE - (size_t)offset; // offset is smaller than MD_USER_DATA_SIZE
if (data_left_to_write <= empty_place_left_in_md)
{
memcpy(&encrypted_part_plain.data[offset], data_to_write, data_left_to_write);
offset += data_left_to_write;
data_to_write += data_left_to_write; // not needed, to prevent future errors
data_left_to_write = 0;
}
else
{
memcpy(&encrypted_part_plain.data[offset], data_to_write, empty_place_left_in_md);
offset += empty_place_left_in_md;
data_to_write += empty_place_left_in_md;
data_left_to_write -= empty_place_left_in_md;
}
if (offset > encrypted_part_plain.size)
encrypted_part_plain.size = offset; // file grew, update the new file size
need_writing = true;
}
while (data_left_to_write > 0)
{
file_data_node_t* file_data_node = NULL;
file_data_node = get_data_node(); // return the data node of the current offset, will read it from disk or create new one if needed (and also the mht node if needed)
if (file_data_node == NULL)
break;
size_t offset_in_node = (size_t)((offset - MD_USER_DATA_SIZE) % NODE_SIZE);
size_t empty_place_left_in_node = NODE_SIZE - offset_in_node;
if (data_left_to_write <= empty_place_left_in_node)
{ // this will be the last write
memcpy(&file_data_node->plain.data[offset_in_node], data_to_write, data_left_to_write);
offset += data_left_to_write;
data_to_write += data_left_to_write; // not needed, to prevent future errors
data_left_to_write = 0;
}
else
{
memcpy(&file_data_node->plain.data[offset_in_node], data_to_write, empty_place_left_in_node);
offset += empty_place_left_in_node;
data_to_write += empty_place_left_in_node;
data_left_to_write -= empty_place_left_in_node;
}
if (offset > encrypted_part_plain.size)
encrypted_part_plain.size = offset; // file grew, update the new file size
if (file_data_node->need_writing == false)
{
file_data_node->need_writing = true;
file_mht_node_t* file_mht_node = file_data_node->parent;
while (file_mht_node->mht_node_number != 0) // set all the mht parent nodes as 'need writing'
{
file_mht_node->need_writing = true;
file_mht_node = file_mht_node->parent;
}
root_mht.need_writing = true;
need_writing = true;
}
}
sgx_thread_mutex_unlock(&mutex);
size_t ret_count = ((size * count) - data_left_to_write) / size;
return ret_count;
}
The inner implementations are in https://github.com/intel/linux-sgx/blob/master/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp.
SDK_PF_New (protected_fs_file::protected_fs_file)
protected_fs_file (SDK_PF_New)static SGX_FILE* sgx_fopen_internal(const char* filename, const char* mode, const sgx_key_128bit_t *auto_key, const sgx_key_128bit_t *kdk_key)
{
protected_fs_file* file = NULL;
if (filename == NULL || mode == NULL)
{
errno = EINVAL;
return NULL;
}
try {
file = new protected_fs_file(filename, mode, auto_key, kdk_key);
}
catch (std::bad_alloc& e) {
(void)e; // remove warning
errno = ENOMEM;
return NULL;
}
if (file->get_error() != SGX_FILE_STATUS_OK)
{
errno = file->get_error();
delete file;
file = NULL;
}
return (SGX_FILE*)file;
}size_t sgx_fwrite(const void* ptr, size_t size, size_t count, SGX_FILE* stream)
{
if (ptr == NULL || stream == NULL || size == 0 || count == 0)
return 0;
protected_fs_file* file = (protected_fs_file*)stream;
return file->write(ptr, size, count);
}
User level APIs are in https://github.com/intel/linux-sgx/blob/master/common/inc/sgx_tprotected_fs.h,
See also: Implementation
/* sgx_fopen
* Purpose: open existing protected file (created with previous call to sgc_fopen) or create a new one (see c++ fopen documentation for more details).
*
* Parameters:
* filename - [IN] the name of the file to open/create.
* mode - [IN] open mode. only supports 'r' or 'w' or 'a' (one and only one of them must be present), and optionally 'b' and/or '+'.
* key - [IN] encryption key that will be used for the file encryption
* NOTE - the key is actually used as a KDK (key derivation key) and only for the meta-data node, and not used directly for the encryption of any part of the file
* this is important in order to prevent hitting the key wear-out problem, and some other issues with GCM encryptions using the same key
*
* Return value:
* SGX_FILE* - pointer to the newly created file handle, NULL if an error occurred - check errno for the error code.
*/
SGX_FILE* SGXAPI sgx_fopen(const char* filename, const char* mode, const sgx_key_128bit_t *key);
/* sgx_fwrite
* Purpose: write data to a file (see c++ fwrite documentation for more details).
*
* Parameters:
* ptr - [IN] pointer to the input data buffer
* size - [IN] size of data block
* count - [IN] count of data blocks to write
* stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key)
*
* Return value:
* size_t - number of 'size' blocks written to the file, 0 in case of an error - check sgx_ferror for error code
*/
size_t SGXAPI sgx_fwrite(const void* ptr, size_t size, size_t count, SGX_FILE* stream);
/* sgx_fread
* Purpose: read data from a file (see c++ fread documentation for more details).
*
* Parameters:
* ptr - [OUT] pointer to the output data buffer
* size - [IN] size of data block
* count - [IN] count of data blocks to write
* stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key)
*
* Return value:
* size_t - number of 'size' blocks read from the file, 0 in case of an error - check sgx_ferror for error code
*/
size_t SGXAPI sgx_fread(void* ptr, size_t size, size_t count, SGX_FILE* stream);
/* sgx_fflush
* Purpose: force actual write of all the cached data to the disk (see c++ fflush documentation for more details).
*
* Parameters:
* stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key)
*
* Return value:
* int32_t - result, 0 on success, 1 in case of an error - check sgx_ferror for error code
*/
int32_t SGXAPI sgx_fflush(SGX_FILE* stream);
int32_t SGXAPI sgx_fclose(SGX_FILE* stream);
int64_t SGXAPI sgx_ftell(SGX_FILE* stream);
int32_t SGXAPI sgx_fseek(SGX_FILE* stream, int64_t offset, int origin);
...
Intel Software Guard Extensions (SGX) offers strong confidentialityand integrity protection to software programs running in untrustedoperating systems. Unfortunately, SGX may be abused by attackersto shield suspicious payloads and conceal misbehaviors in SGXenclaves, which cannot be easily detected by existing defense solu-tions. There is no comprehensive study conducted to characterizemalicious enclaves. In this paper, we present the first systematicstudy that scrutinizes all possible interaction interfaces betweenenclaves and the outside (i.e., cache-memory hierarchy, host vir-tual memory, and enclave-mode transitions), and identifies sevenattack vectors. Moreover, we proposeSGX-Bouncer, a detectionframework that can detect these attacks by leveraging multifariousside-channel observations and SGX-specific features. We conductempirical evaluations with existing malicious SGX applications,which suggestsSGX-Bouncercan effectively detect various abnor-mal behaviors from malicious enclaves.
Need updates
class protected_fs_file
{
private:
union {
struct {
uint64_t meta_data_node_number; // for recovery purpose, so it is easy to write this node
meta_data_node_t file_meta_data; // actual data from disk's meta data node
};
recovery_node_t meta_data_recovery_node;
};
meta_data_encrypted_t encrypted_part_plain; // encrypted part of meta data node, decrypted
file_mht_node_t root_mht; // the root of the mht is always needed (for files bigger than 3KB)
FILE* file; // OS's FILE pointer
open_mode_t open_mode;
uint8_t read_only;
int64_t offset; // current file position (user's view)
bool end_of_file; // flag
int64_t real_file_size;
bool need_writing; // flag
uint32_t last_error; // last operation error
protected_fs_status_e file_status;
sgx_thread_mutex_t mutex;
uint8_t use_user_kdk_key;
sgx_aes_gcm_128bit_key_t user_kdk_key; // recieved from user, used instead of the seal key
sgx_aes_gcm_128bit_key_t cur_key;
sgx_aes_gcm_128bit_key_t session_master_key;
uint32_t master_key_count;
char recovery_filename[RECOVERY_FILE_MAX_LEN]; // might include full path to the file
lru_cache cache;
// these don't change after init...
sgx_iv_t empty_iv;
sgx_report_t report;
void init_fields();
bool cleanup_filename(const char* src, char* dest);
bool parse_mode(const char* mode);
bool file_recovery(const char* filename);
bool init_existing_file(const char* filename, const char* clean_filename, const sgx_aes_gcm_128bit_key_t* import_key);
bool init_new_file(const char* clean_filename);
bool generate_secure_blob(sgx_aes_gcm_128bit_key_t* key, const char* label, uint64_t physical_node_number, sgx_aes_gcm_128bit_tag_t* output);
bool generate_secure_blob_from_user_kdk(bool restore);
bool init_session_master_key();
bool derive_random_node_key(uint64_t physical_node_number);
bool generate_random_meta_data_key();
bool restore_current_meta_data_key(const sgx_aes_gcm_128bit_key_t* import_key);
file_data_node_t* get_data_node();
file_data_node_t* read_data_node();
file_data_node_t* append_data_node();
file_mht_node_t* get_mht_node();
file_mht_node_t* read_mht_node(uint64_t mht_node_number);
file_mht_node_t* append_mht_node(uint64_t mht_node_number);
bool write_recovery_file();
bool set_update_flag(bool flush_to_disk);
void clear_update_flag();
bool update_all_data_and_mht_nodes();
bool update_meta_data_node();
bool write_all_changes_to_disk(bool flush_to_disk);
void erase_recovery_file();
bool internal_flush(/*bool mc,*/ bool flush_to_disk);
public:
protected_fs_file(const char* filename, const char* mode, const sgx_aes_gcm_128bit_key_t* import_key, const sgx_aes_gcm_128bit_key_t* kdk_key);
~protected_fs_file();
size_t write(const void* ptr, size_t size, size_t count);
size_t read(void* ptr, size_t size, size_t count);
int64_t tell();
int seek(int64_t new_offset, int origin);
bool get_eof();
uint32_t get_error();
void clear_error();
int32_t clear_cache();
bool flush(/*bool mc*/);
bool pre_close(sgx_key_128bit_t* key, bool import);
static int32_t remove(const char* filename);
};
Intel SGX isolates the memory of security-critical applications from the untrusted OS. However, it has been speculated that SGX may be vulnerable to side-channel attacks through shared caches. We developed new cache attack techniques customized for SGX. Our attack differs from other SGX cache attacks in that it is easy to deploy and avoids known detection approaches. We demonstrate the effectiveness of our attack on two case studies: RSA decryption and genomic processing. While cache timing attacks against RSA and other cryptographic operations can be prevented by using appropriately hardened crypto libraries, the same cannot be easily done for other computations, such as genomic processing. Our second case study therefore shows that attacks on non-cryptographic but privacy sensitive operations are a serious threat. We analyze countermeasures and show that none of the known defenses eliminates the attack.
In Figure 2, the attacker will observe an increased access time for cache line 2. Since the attacker knows the code and access pattern of the victim, he knows that address X of the victim maps to cache line 2, and that the sensitive key-bit must be zero.
Generated List: